package tc.jv.task8;

import java.util.ArrayList;

import tc.jv.task4.AbstractVector;
import tc.jv.task4.Vector;
import tc.jv.task8.observer.Observable;
import tc.jv.task8.observer.Observer;
import tc.jv.task9.IncompatibleVectorSizeException;

public class ObservableVector extends AbstractVector implements Observable
{

	/**
	 * 
	 */
	private static final long serialVersionUID = 6373994733504350908L;

	private Vector vector;
	
	private ArrayList<Observer> observers = new ArrayList<Observer>();
	
	// CONSTRUCTORS
	
	public ObservableVector()
	{
		vector = Vectors.createInstance();
	}
	
	public ObservableVector(Vector vector)
	{
		this.vector = vector;
	}
	
	// ACCESSORS
	
	public int size()
	{
		return vector.size();
	}
	
	public double get(int index)
	{
		return vector.get(index);
	}
	
	public double set(int index, double value)
	{
		double result = vector.set(index, value);
		notifyObserversElementUpdate(index);
		return result;
	}
	
	// SUPERCLASS METHODS
	
	@Override
	@SuppressWarnings("unchecked")
	public Object clone()
	{
		ObservableVector ov = null;
		
		ov = (ObservableVector) super.clone();
		ov.vector = (Vector) this.vector.clone();
		ov.observers = (ArrayList<Observer>) this.observers.clone();
		
		return ov;
		
	}

	public boolean equals(Object obj)
	{
		return vector.equals(obj);
	}

	public int hashCode()
	{
		return vector.hashCode();
	}

	public String toString()
	{
		return vector.toString();
	}
	
	// METHODS
	
	public String toString(int pcs)
	{
		return vector.toString(pcs);
	}
	
	public void print()
	{
		vector.print();
	}
	
	public void print(int pcs)
	{
		vector.print(pcs);
	}
	
	public void addFirst(double value)
	{
		vector.addFirst(value);
		notifyObserversElementUpdate(0);
	}
	
	public void addLast(double value)
	{
		vector.addLast(value);
		notifyObserversElementUpdate(size()-1);
	}
	
	public void add(double value)
	{
		vector.add(value);
		notifyObserversElementUpdate(size()-1);
	}
	
	public boolean add(int index, double value)
	{
		boolean result = vector.add(index, value);
		notifyObserversElementUpdate(index);
		return result;
	}
	
	public double remove(int index)
	{
		double result = vector.remove(index);
		notifyObserversElementUpdate(index);
		return result;
	}
	
	public boolean fill(double[] array) throws IncompatibleVectorSizeException
	{
		boolean result = vector.fill(array);
		notifyObserversVectorUpdate();
		return result;
	}

	public boolean fill(double[] array, int position) throws IncompatibleVectorSizeException
	{
		boolean result = vector.fill(array, position);
		notifyObserversVectorUpdate();
		return result;
	}
	
	public boolean fill(Vector v) throws IncompatibleVectorSizeException
	{
		boolean result = vector.fill(v);
		notifyObserversVectorUpdate();
		return result;
	}
	
	public boolean fill(Vector v, int position) throws IncompatibleVectorSizeException
	{
		boolean result = vector.fill(v, position);
		notifyObserversVectorUpdate();
		return result;
	}

	public boolean sum(Vector v) throws IncompatibleVectorSizeException
	{
		boolean result = vector.sum(v);
		notifyObserversVectorUpdate();
		return result;
	}
	
	public boolean sum(Vector v, int position) throws IncompatibleVectorSizeException
	{
		boolean result = vector.sum(v, position);
		notifyObserversVectorUpdate();
		return result;
	}
	
	public boolean multiply(double multiplicator)
	{
		boolean result = vector.multiply(multiplicator);
		notifyObserversVectorUpdate();
		return result;
	}
	
	////////////////////////
	// OBSERVABLE METHODS //
	////////////////////////
	
	public void addObserver(Observer obs)
	{
		observers.add(obs);
	}
	
	public void removeObserver(Observer obs)
	{
		observers.remove(obs);
	}
	
	public void notifyObserversElementUpdate(int index)
	{
		for (Observer obs : observers)
			obs.elementUpdateEvent(index);
	}
	
	public void notifyObserversVectorUpdate()
	{
		for (Observer obs : observers)
			obs.vectorUpdateEvent();
	}

}
